#include "ScnsDht11.c.h"

#if defined(SCNS_DHT11_ENABLE)&&SCNS_DHT11_ENABLE==1

//@scnsBsp:https://gitee.com/huoxingdawang/scnsDemos-STM32F767IGT6_AlientekApollo/tree/master/Libraries/scnsBsp/STM32F767IGT6_AlientekApollo/

#include "ScnsTimer.h"

static struct
{
    uint8 inited;
    uint64 us;
}rd[SCNS_DHT11_MAX];

ScnsDht11Result scnsDht11Result[SCNS_DHT11_MAX];

void reset(ScnsDht11Enum dhtN)
{
    scnsBspDht11SetDir(dhtN,0);
    scnsBspDht11Set(dhtN,0);
    scnsDelayMs(20);
    scnsBspDht11Set(dhtN,1);
    scnsDelayUs(30);
}

static uint8 check(ScnsDht11Enum dhtN)
{
    uint8 retry=0;
    scnsBspDht11SetDir(dhtN,1);
    while(scnsBspDht11Get(dhtN)&&retry<100)
    {
        retry++;
        scnsDelayUs(1);
    }
    if(retry>=100)return 1;
    else retry=0;
    while(!scnsBspDht11Get(dhtN)&&retry<100)
    {
        retry++;
        scnsDelayUs(1);
    }
    if(retry>=100)return 1;
    return 0;
}

static uint8 Rb(ScnsDht11Enum dhtN)
{
    uint8 retry=0;
    while(scnsBspDht11Get(dhtN)&&retry<100)
    {
        retry++;
        scnsDelayUs(1);
    }
    retry=0;
    while(!scnsBspDht11Get(dhtN)&&retry<100)
    {
        retry++;
        scnsDelayUs(1);
    }
    scnsDelayUs(40);
    if(scnsBspDht11Get(dhtN))return 1;
    else return 0;
}

static uint8 RB(ScnsDht11Enum dhtN)
{
    uint8 i,dat;
    dat=0;
    for(i=0;i<8;i++)
    {
        dat<<=1;
        dat|=Rb(dhtN);
    }
    return dat;
}

static ScnsDht11Status RD(ScnsDht11Enum dhtN,uint8 buf[5])
{
    reset(dhtN);
    if(check(dhtN)==0)
    {
        for(uint8 i=0;i<5;++i)
            buf[i]=RB(dhtN);
        if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
        {
            scnsDht11Result[SCNS_DHT11_1].temperature=buf[0];
            scnsDht11Result[SCNS_DHT11_1].humidity=buf[2];
            return SCNS_DHT11_STATUS_OK;
        }
    }
    return SCNS_DHT11_STATUS_FAILED;
}

static uint8 rc(ScnsDht11Enum dhtN)
{
    reset(dhtN);
    return check(dhtN);
}

ScnsDht11Status scnsDht11Init(ScnsDht11Enum dhtN)
{
    SCNS_ASSERT_ON_RUN(dhtN<SCNS_DHT11_MAX);
    scnsCheck(ScnsDht11Status,scnsBspDht11Init(dhtN),SCNS_DHT11_STATUS_OK);
    scnsCheckTimeOut(200*1000,rc(dhtN)==0,SCNS_DHT11_STATUS_TIME_OUT);
    uint8 buf[5];
    scnsCheckTimeOut(200*1000,RD(dhtN,buf)==SCNS_DHT11_STATUS_OK,SCNS_DHT11_STATUS_CRC_FAILED);
    scnsCheck(ScnsDht11Status,scnsBspDht11PostInit(dhtN),SCNS_DHT11_STATUS_OK);
    rd[dhtN].inited=1;
    return SCNS_DHT11_STATUS_OK;
}

void scnsDht11Interrupt(ScnsDht11Enum dhtN)
{
    SCNS_ASSERT_ON_RUN(dhtN<SCNS_DHT11_MAX);
    if(!rd[dhtN].inited)
        return;
    const uint64 t=scnsTimerGetUs();
    if(100*1000+rd[dhtN].us>=t)
        return;
    rd[dhtN].us=t;
    
    uint8 buf[5];
    if(SCNS_DHT11_STATUS_OK!=RD(dhtN,buf))return;
    
    scnsDht11Result[SCNS_DHT11_1].humidity=buf[0];
    scnsDht11Result[SCNS_DHT11_1].temperature=buf[2];
    scnsBspDht11ResultUpdate(dhtN);
}

#endif
